package com.langshixiaobai.mqdemo.server.datacenter;

import com.langshixiaobai.mqdemo.common.MqException;
import com.langshixiaobai.mqdemo.server.core.Binding;
import com.langshixiaobai.mqdemo.server.core.Exchange;
import com.langshixiaobai.mqdemo.server.core.MSGQueue;
import com.langshixiaobai.mqdemo.server.core.Message;

import javax.swing.plaf.PanelUI;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

//内存数据中心
public class MemoryDataCenter {

    //key 为 queueName 、value 为 MSGQueue对象
    private ConcurrentHashMap<String, MSGQueue> queueHashMap = new ConcurrentHashMap<>();
    //key 为 exchangeName 、 value 为 Exchange对象
    private ConcurrentHashMap<String, Exchange> exchangeHashMap = new ConcurrentHashMap<>();
    //绑定信息，key 为 exchangeName ， value 中 key 为 queueName 、 value 为 Binding 信息
    private ConcurrentHashMap<String, ConcurrentHashMap<String, Binding>> bingsMap = new ConcurrentHashMap<>();
    //虽然下面Message对象存在两个Map中，但是实际上Message对象在内存中只有一份，存的是指向Message对象的引用，所以不占用空间
    //通过messageId获取消息
    private ConcurrentHashMap<String, Message> messageMap = new ConcurrentHashMap<>();
    //key 为 queueName 、 value 为 Message集合
    private ConcurrentHashMap<String, LinkedList<Message>> queueMessageMap = new ConcurrentHashMap<>();
    //key 为 queueName ， value 中 key 为 messageId 、 value 为 message对象
    // 用来确认是否返回ACK，hashmap比链表更适合查删改
    private ConcurrentHashMap<String, ConcurrentHashMap<String, Message>> queueMessageAckMap = new ConcurrentHashMap<>();


    public void insertQueue(MSGQueue queue) {
        queueHashMap.put(queue.getName(), queue);
        System.out.println("[MemoryDataCenter]添加队列：" + queue.getName());
    }

    public MSGQueue getQueue(String queueName) {
        System.out.println("[MemoryDataCenter]获取：" + queueName);
        return queueHashMap.get(queueName);
    }

    public void insertExchange(Exchange exchange) {
        exchangeHashMap.put(exchange.getName(), exchange);
        System.out.println("[MemoryDataCenter]添加交换机：" + exchange.getName());
    }

    public Exchange getExchange(String exchangeName) {
        System.out.println("[MemoryDataCenter]添加交换机：" + exchangeName);
        return exchangeHashMap.get(exchangeName);
    }

    public void insertBinding(Binding binding) throws MqException {
        //computeIfAbsent()方法，当value存在时，返回value，不存在时则返回第二个参数所写的东西（下面是返回一个new hashMap）
        ConcurrentHashMap<String, Binding> bindingConcurrentHashMap = bingsMap.computeIfAbsent(binding.getExchangeName(), k -> new ConcurrentHashMap<String, Binding>());

        synchronized (bindingConcurrentHashMap) {
            //说明当前map中已经存有绑定关系，返回异常
            if (bindingConcurrentHashMap.get(binding.getQueueName()) != null) {
                throw new MqException("[MemoryDataCenter]已经有绑定关系");
            }
            //
            bindingConcurrentHashMap.put(binding.getQueueName(), binding);

            bingsMap.put(binding.getExchangeName(), bindingConcurrentHashMap);

            System.out.println("[MemoryDataCenter]添加绑定关系：" + binding.getBindingKey());

        }
    }

    //通过Binding对象获取绑定关系
    public Binding getBinding(Binding binding) {
        ConcurrentHashMap<String, Binding> bindingConcurrentHashMap = bingsMap.get(binding.getExchangeName());
        if (bindingConcurrentHashMap == null) {
            return null;
        }
        System.out.println("[MemoryDataCenter]获取绑定关系通过 Binding：" + binding.getBindingKey());
        return bindingConcurrentHashMap.get(binding.getQueueName());
    }

    //通过exchangeName获取绑定关系
    public ConcurrentHashMap<String, Binding> getBindings(String exchangeName) {
        ConcurrentHashMap<String, Binding> bindingConcurrentHashMap = bingsMap.get(exchangeName);
        if (bindingConcurrentHashMap == null) {
            return null;
        }
        System.out.println("[MemoryDataCenter]获取绑定关系通过exchangeName：" + exchangeName);
        return bindingConcurrentHashMap;
    }

    //删除绑定关系
    public void deleteBinding(Binding binding) throws MqException {
        ConcurrentHashMap<String, Binding> bindingConcurrentHashMap = bingsMap.get(binding.getExchangeName());
        if (bindingConcurrentHashMap == null) {
            throw new MqException("[MemoryDataCenter]绑定关系不存在，删除失败");
        }
        bindingConcurrentHashMap.remove(binding.getExchangeName(), bindingConcurrentHashMap);

        System.out.println("[MemoryDataCenter]删除绑定关系：" + binding.getBindingKey());

    }


    //添加消息
    public void insertMessage(Message message) {
        messageMap.put(message.getMessageId(), message);
        System.out.println("[MemoryDataCenter]添加消息：" + message.getMessageId());
    }

    //获取消息
    public Message getMessage(String messageId) {
        System.out.println("[MemoryDataCenter]获取消息：" + messageId);
        return messageMap.get(messageId);
    }

    //删除消息
    public void deleteMessage(String messageId) throws MqException {
        Message message = messageMap.get(messageId);
        if (message == null) {
            throw new MqException("[MemoryDataCenter]消息不存在：" + messageId);
        }
        messageMap.remove(messageId, message);
    }
}
